package com.stars.easyms.proxy;

import com.stars.easyms.base.bean.LazyLoadBean;
import com.stars.easyms.base.constant.HttpHeaderConstants;
import com.stars.easyms.base.encrypt.EasyMsEncrypt;
import com.stars.easyms.base.enums.EncryptTypeEnum;
import com.stars.easyms.proxy.exception.EasyMsProxyRuntimeException;
import com.stars.easyms.proxy.properties.EasyMsProxyProperties;
import com.stars.easyms.proxy.service.EasyMsRestProxyService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

/**
 * <p>className: EasyMsRestProxyService</p>
 * <p>description: EasyMsRest代理服务类</p>
 *
 * @author guoguifang
 * @version 1.7.3
 * @date 2021/3/5 11:30 上午
 */
public class BaseEasyMsRestProxyService implements EasyMsRestProxyService {

    private final LazyLoadBean<EasyMsProxyProperties> easyMsProxyProperties = new LazyLoadBean<>(EasyMsProxyProperties.class);

    private final LazyLoadBean<RestTemplate> restTemplate = new LazyLoadBean<>(RestTemplate.class);

    @Override
    public String restProxy(String targetCode, String url, String path, String arg) {
        if (StringUtils.isBlank(path)) {
            throw new EasyMsProxyRuntimeException("代理目标path不能为空!");
        }
        EasyMsProxyProperties.Target target = getTarget(targetCode);
        url = formatUrl(StringUtils.isBlank(url) ? target.getAddr() : url, path);
        Object requestObj = getEncryptRequestObj(target, arg);
        HttpHeaders headers = new HttpHeaders();
        headers.set(HttpHeaderConstants.HEADER_KEY_REQUEST_SOURCE, easyMsProxyProperties.getNonNullBean().getName());
        HttpEntity requestEntity = new HttpEntity<>(requestObj, headers);
        ResponseEntity<String> responseEntity = restTemplate.getNonNullBean().postForEntity(url, requestEntity, String.class);
        if (responseEntity.getStatusCode() != HttpStatus.OK) {
            throw new EasyMsProxyRuntimeException(responseEntity.getStatusCode().getReasonPhrase());
        }
        return getDecodeResponseObj(target, responseEntity.getBody());
    }

    @Override
    public String restProxy(String targetCode, String path, String arg) {
        return restProxy(targetCode, null, path, arg);
    }

    @Override
    public String restProxy(String path, String arg) {
        return restProxy(null, null, path, arg);
    }

    private Object getEncryptRequestObj(EasyMsProxyProperties.Target target, Object requestObj) {
        EasyMsProxyProperties.Encrypt encrypt = target.getEncrypt();
        if (encrypt.isEnabled()) {
            if (EncryptTypeEnum.SYMMETRIC == encrypt.getType()) {
                EasyMsProxyProperties.Symmetric symmetric = encrypt.getSymmetric();
                requestObj = EasyMsEncrypt.encrypt(requestObj, symmetric.getSecret(), symmetric.getIv(), symmetric.getKey());
            }
            // todo:非对称加密
        }
        return requestObj;
    }

    private String getDecodeResponseObj(EasyMsProxyProperties.Target target, String responseObj) {
        EasyMsProxyProperties.Encrypt encrypt = target.getEncrypt();
        if (encrypt.isEnabled()) {
            if (EncryptTypeEnum.SYMMETRIC == encrypt.getType()) {
                EasyMsProxyProperties.Symmetric symmetric = encrypt.getSymmetric();
                return EasyMsEncrypt.decode(responseObj, symmetric.getSecret(), symmetric.getIv(), symmetric.getKey());
            }
            // todo:非对称加密
        }
        return responseObj;
    }

    private EasyMsProxyProperties.Target getTarget(String code) {
        if (StringUtils.isBlank(code)) {
            return easyMsProxyProperties.getNonNullBean().getTarget();
        }
        EasyMsProxyProperties.Target target = easyMsProxyProperties.getNonNullBean().getTargets().get(code);
        if (target == null) {
            throw new EasyMsProxyRuntimeException("根据targetCode({}})找不到对应的target!", code);
        }
        return target;
    }

    private String formatUrl(String addr, String path) {
        if (StringUtils.isBlank(addr)) {
            return path;
        }
        while (addr.endsWith("/")) {
            addr = addr.substring(0, addr.length() - 1);
        }
        return addr + (path.startsWith("/") ? "" : "/") + path;
    }
}
